#pragma once

#include "muduo/net/Channel.h"
#include "muduo/net/EventLoop.h"

#include <opencv2/opencv.hpp>
#include <rclcpp/rclcpp.hpp>

#include <atomic>

namespace sensor::camera {

struct CameraOneFrame {
    cv::Mat image;
};

class CameraReceiver {
protected:
    using OneFrameCallback = std::function<void(std::shared_ptr<CameraOneFrame>)>;

public:
    CameraReceiver(const std::string& rxer, std::string dev, muduo::net::EventLoop* loop,
        size_t width, size_t height, const std::string& fmt);
    virtual ~CameraReceiver();

    bool enable();
    void disable();
    void setOneFrameCallback(const OneFrameCallback& cb);

private:
    bool getCameraCapcity();

    bool setCameraFormat();
    bool getCameraFormat();

    bool startVideoCapture();
    bool stopVideoCapture();

    virtual bool prepareBuffers() = 0;
    virtual void releaseBuffers() = 0;

    virtual void onReceiveOneFrame() = 0;

    void releaseChannel();

protected:
    rclcpp::Logger logger_;
    const std::string video_dev_;
    muduo::net::EventLoop* loop_;
    size_t width_ = 1920;
    size_t height_ = 1080;
    size_t pix_format_ = -1;

    std::atomic<bool> enabled_ { false };
    std::unique_ptr<muduo::net::Channel> chnl_;
    OneFrameCallback cb_;

    static std::unordered_map<std::string, int> camera_pix_format_table_;
};

}